package com.ccteam.admin.viewmodels.artist

import android.app.Application
import androidx.lifecycle.*
import com.ccteam.admin.R
import com.ccteam.admin.core.ADD_TYPE
import com.ccteam.admin.core.EDIT_TYPE
import com.ccteam.admin.repositories.ArtistAdminRepository
import com.ccteam.admin.repositories.UploadAdminRepository
import com.ccteam.admin.utils.*
import com.ccteam.admin.vo.Resource
import com.ccteam.model.artist.ArtistInfoDTO
import com.ccteam.model.artist.ArtistInfoNoIdDTO
import com.ccteam.model.artist.ArtistVO
import com.ccteam.network.ApiError
import com.ccteam.network.exception.ApiException
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
import kotlin.coroutines.suspendCoroutine

/**
 * @author Xiaoc
 * @since 2021/2/7
 **/
@HiltViewModel
class ArtistEditViewModel @Inject constructor(
    application: Application,
    private val artistAdminRepository: ArtistAdminRepository,
    private val uploadRepository: UploadAdminRepository,
    savedStateHandle: SavedStateHandle,
    private val uploadFileUtils: UploadFileUtils
) : AndroidViewModel(application) {

    @Volatile
    private var shouldCancel: Boolean = false

    /**
     * 歌手名内容是否成功
     */
    private val artistNameSuccess = MutableLiveData(false)

    /**
     * 歌手头像内容是否成功
     */
    private val artistUrlSuccess = MutableLiveData(false)

    private val _editButtonEnable = MediatorLiveData<Boolean>()
    val editButtonEnable: LiveData<Boolean> get() = _editButtonEnable

    private val _deleteButtonEnable = MediatorLiveData<Boolean>()
    val deleteButtonEnable: LiveData<Boolean> get() = _deleteButtonEnable

    /**
     * 最原始的歌手信息（例如编辑时最初的歌手信息，方便与修改后的作比较）
     */
    private var originArtistInfo: ArtistEditInfo? = null

    private val _editArtistInfo = MediatorLiveData<ArtistEditInfo>()
    val editArtistInfo: LiveData<ArtistEditInfo> get() = _editArtistInfo

    private val artistIdLiveData = MutableLiveData<String>()

    private val _loadingMessage = MutableLiveData<LoadMessage>(LoadMessage.NotLoading)
    val loadMessage: LiveData<LoadMessage> get() = _loadingMessage

    /**
     * 编辑时的加载信息
     */
    private val _editLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val editLoadMessage: LiveData<Event<LoadMessage>> get() = _editLoadMessage

    /**
     * 删除时的加载信息
     */
    private val _deleteLoadMessage = MediatorLiveData<Event<LoadMessage>>()
    val deleteLoadMessage: LiveData<Event<LoadMessage>> get() = _deleteLoadMessage

    /**
     * 当前类型为 编辑歌手 or 新增歌手
     * 仅可赋值一次
     */
    private var type: Int? = savedStateHandle["artistEditType"] ?: ADD_TYPE

    init {
        _editButtonEnable.addSource(artistNameSuccess) {
            _editButtonEnable.value = it && artistUrlSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(artistUrlSuccess) {
            _editButtonEnable.value = it && artistNameSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_editLoadMessage) {
            val enable = it.peekContent() !is LoadMessage.Loading
                    && artistUrlSuccess.value == true && artistNameSuccess.value == true
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _deleteLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editButtonEnable.addSource(_deleteLoadMessage) {
            val enable = it.peekContent() !is LoadMessage.Loading
                    && artistUrlSuccess.value == true && artistNameSuccess.value == true
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
            _editButtonEnable.value = enable
            _deleteButtonEnable.value = it.peekContent() !is LoadMessage.Loading
                    && _editLoadMessage.value?.peekContent() !is LoadMessage.Loading
        }

        _editArtistInfo.addSource(artistIdLiveData) {
            refreshArtistInfo()
        }

        artistIdLiveData.setValueIfNew(savedStateHandle["artistId"])

        if (type == ADD_TYPE) {
            _editArtistInfo.value = ArtistEditInfo()
        }

    }

    /**
     * 设置歌手封面地址
     */
    fun setArtistImgUrl(imgUrl: String) {
        _editArtistInfo.value?.imgUrl = imgUrl
    }

    /**
     * 设置歌手封面是否成功
     */
    fun setArtistImgUrlSuccess(isSuccess: Boolean) {
        artistUrlSuccess.value = isSuccess
    }

    /**
     * 设置歌手名
     */
    fun setArtistName(artistName: String) {
        _editArtistInfo.value?.name = artistName
    }

    /**
     * 设置歌手名是否成功
     */
    fun setArtistNameSuccess(isSuccess: Boolean) {
        artistNameSuccess.value = isSuccess
    }

    /**
     * 更新编辑后的专辑信息，因为在外部设置不同的更新属性时会导致一些问题
     * 所以手动提供此方法进行调用
     */
    fun updateArtistEditInfo() {
        _editArtistInfo.value = _editArtistInfo.value
    }

    /**
     * 上传歌手头像
     */
    private suspend fun uploadArtistPhoto(photoUri: String?) {
        val application = getApplication<Application>()

        if (photoUri?.startsWith("content://") == false) {
            setArtistImgUrl(photoUri)
            return
        }

        val result = uploadRepository.getImageToken()
        // 检测token是否获取成功
        if (result !is Resource.Success || result.data.isNullOrEmpty()) {
            throw ApiException(ApiError.serverErrorCode, "获取Token失败")
        }
        val token = result.data

        suspendCoroutine<String> { cn ->
            viewModelScope.launch{
                uploadFileUtils.upload(application, token, photoUri, { }, { fileUrl ->
                    setArtistImgUrl(fileUrl)
                    cn.resume(fileUrl)
                }, { errorMessage ->
                    cn.resumeWithException(ApiException(ApiError.serverErrorCode, errorMessage))
                })
            }
        }

    }

    /**
     * 编辑和发布时调用此方法
     * 会先进行正确性检验，如果失败，会发出 [errorMessage] 提示相关信息
     * 如果正确，则直接进行对应内容的提交
     */
    fun editOrAddArtistInfo() {
        val application = getApplication<Application>()
        if (_editButtonEnable.value != true || _editArtistInfo.value == null) {
            _editLoadMessage.value = Event(
                LoadMessage.Error(
                    ErrorMessage(
                        ApiError.unknownCode,
                        application.getString(R.string.description_other_error)
                    )
                )
            )
            return
        }

        if (_editArtistInfo.value == originArtistInfo) {
            _editLoadMessage.value = Event(
                LoadMessage.Error(
                    ErrorMessage(
                        ApiError.unknownCode,
                        application.getString(R.string.description_error_equal)
                    )
                )
            )
            return
        }

        _editLoadMessage.value = Event(LoadMessage.Loading)

        /**
         * 上传前会检测头像是否为本地的头像，如果为本地头像
         * 则先上传获得文件地址后再更新内容
         */
        viewModelScope.launch(
            CoroutineExceptionHandler { c, throwable ->
                val errorMessage = if (throwable is ApiException) {
                    ErrorMessage(throwable.errorCode, throwable.message)
                } else {
                    ErrorMessage(ApiError.unknownCode, throwable.message)
                }
                _editLoadMessage.value = Event(LoadMessage.Error(errorMessage))
            }
        ) {
            uploadArtistPhoto(_editArtistInfo.value?.imgUrl)
            handleRequestEditAddArtistInfo()
        }

    }

    /**
     * 删除歌手信息
     */
    fun deleteArtistInfo() {
        // 将其设置为 请求中 状态
        _deleteLoadMessage.value = Event(LoadMessage.Loading)

        artistIdLiveData.value?.let {
            viewModelScope.launch {
                val result = artistAdminRepository.deleteArtist(it)
                handleDeleteResult(result)
            }
        }
    }

    fun refreshArtistInfo() {
        _loadingMessage.value = LoadMessage.Loading
        artistIdLiveData.value?.let { artistId ->
            viewModelScope.launch {

                val result = artistAdminRepository.getArtist(artistId)

                if (result is Resource.Success) {
                    _loadingMessage.value = LoadMessage.NotLoading

                    originArtistInfo = ArtistEditInfo.toArtistEditInfo(result.data)
                    _editArtistInfo.value = ArtistEditInfo.toArtistEditInfo(result.data)

                } else {
                    _loadingMessage.value =
                        LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode, result.message))
                }
            }
        }
    }

    private fun handleRequestEditAddArtistInfo() {
        // 将其设置为 请求中 状态
        _editLoadMessage.value = Event(LoadMessage.Loading)

        viewModelScope.launch {
            // 根据不同的类型进行不同的API调用请求
            val result = if (type == EDIT_TYPE) {
                artistAdminRepository.editArtist(_editArtistInfo.value!!.toEditArtistInfoDto())
            } else {
                artistAdminRepository.addArtist(_editArtistInfo.value!!.toAddArtistNoIdDto())
            }
            handleEditResult(result)
        }
    }

    private fun handleEditResult(result: Resource<Nothing?>) {
        if (result is Resource.Success) {
            _editLoadMessage.value = Event(LoadMessage.Success)
        } else {
            _editLoadMessage.value =
                Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode, result.message)))
        }
    }

    private fun handleDeleteResult(result: Resource<Nothing?>) {
        if (result is Resource.Success) {
            _deleteLoadMessage.value = Event(LoadMessage.Success)
        } else {
            _deleteLoadMessage.value =
                Event(LoadMessage.Error(ErrorMessage(ApiError.serverErrorCode, result.message)))
        }
    }

    /**
     * Artist歌手编辑的数据类
     * 使用该类是因为该类字段允许全为空，且具备基本的判断功能
     */
    data class ArtistEditInfo(
        var id: String? = null,
        var imgUrl: String? = null,
        var name: String? = null
    ) {
        companion object {

            /**
             * 将 [ArtistInfoVO] 转化为 [ArtistEditInfo] 具有更精简的信息
             */
            fun toArtistEditInfo(artistInfoVO: ArtistVO?): ArtistEditInfo {
                return ArtistEditInfo(artistInfoVO?.id, artistInfoVO?.imgUrl, artistInfoVO?.name)
            }
        }

        /**
         * 将 [ArtistEditInfo] 转换为 提交编辑歌手API需要的 [ArtistInfoDto]
         * 意味着该内容是编辑歌手
         */
        fun toEditArtistInfoDto(): ArtistInfoDTO {
            return ArtistInfoDTO(
                id!!,
                imgUrl!!,
                name!!
            )
        }

        /**
         * 将 [ArtistEditInfo] 转换为 提交新增歌手API需要的 [ArtistInfoNoIdDto]
         * 意味着该内容是新增歌手，所以 trackNum 和 albumNum 为 0
         */
        fun toAddArtistNoIdDto(): ArtistInfoNoIdDTO {
            return ArtistInfoNoIdDTO(imgUrl!!, name!!)
        }


    }

}